#ifndef G3_FRUSTUM_H
#define G3_FRUSTUM_H

#include "log.h"
#include "types.h"
#include "color.h"

#include "math/m_plane.h"
#include "math/m_matrix.h"
#include "math/m_bounding.h"
#include "math/m_intersection.h"

#include <GL/gl.h>

namespace G3 {

enum FRUSTUM_PLANE {
     GF_LEFT = 0,
     GF_RIGHT = 1,
     GF_TOP = 2,
     GF_BOTTOM = 3,
     GF_NEAR = 4,
     GF_FAR = 5
};

enum FRUSTUM_CORNER {
     GF_NEAR_TOPLEFT = 0,
     GF_NEAR_TOPRIGHT = 1,
     GF_NEAR_BOTTOMLEFT = 2,
     GF_NEAR_BOTTOMRIGHT = 3,
     GF_FAR_TOPLEFT = 4,
     GF_FAR_TOPRIGHT = 5,
     GF_FAR_BOTTOMLEFT = 6,
     GF_FAR_BOTTOMRIGHT = 7
};

enum FRUSTUM_INTERSECTION {
	GF_TOPLEFT = 0,
	GF_TOPRIGHT = 1,
	GF_BOTTOMLEFT = 2,
	GF_BOTTOMRIGHT = 3,
	GF_NEARLEFT = 4,
	GF_NEARRIGHT = 5,
	GF_NEARTOP = 6,
	GF_NEARBOTTOM = 7,
	GF_FARLEFT = 8,
	GF_FARRIGHT = 9,
	GF_FARTOP = 10,
	GF_FARBOTTOM = 11,
};

enum FRUSTUM_CLASSIFIC {
     GFC_OUT = 0,
     GFC_HALF = 1,
     GFC_IN = 2
};

//Make sure that you reconstruct this frustum and store it
//in your camera class each time the view or projection matrix
//changes and NOT each time you perform an intersection test.

//Dion Picco

class FRUSTUM {
	public:
		FRUSTUM ();

        PLANE3F Plane [6];
	    VEC3F Corner [8];
	    AABB3F BBox;
		INTERSECTION3F Intersections [12];

       	float FieldOfView;
	   	float AspectRatio;
        float NearPlane;
        float FarPlane;

		VEC3F Origin;

		VEC3F UpVector;
		VEC3F RightVector;
		VEC3F ForwardVector;

		FRUSTUM& operator= (const FRUSTUM &f);

//==============================================================================
// Extracts the View Frustum from a matrix
//==============================================================================
       	bool Extract (MATRIX4x4F *M);
       	bool Extract (float M [16]);

//==============================================================================
// Extracts the View Frustum from OpenGL Projection and Modelview matrices
//==============================================================================
       	bool glExtract ();

//==============================================================================
// Is the point in the frustum?
//==============================================================================
       	bool IsPointIn (VEC3F P);

//==============================================================================
// Is the sphere in the frustum, out of it, or spanning?
//==============================================================================
       	FRUSTUM_CLASSIFIC IsSphereIn (const BSPH3F &sphere) const;

//==============================================================================
// Is the box in the frustum, out of it, or spanning?
//==============================================================================
       	FRUSTUM_CLASSIFIC IsBoxIn (const AABB3F &box) const;

//==============================================================================
// Sets aspect ratio according to the given window dimensions
//==============================================================================
		void SetAspectRatio (uint Width, uint Height);

//==============================================================================
// Sets the field of view angle (in degrees)
//==============================================================================
		void SetFieldOfView (float FOV);

//==============================================================================
// Sets the Near and Far plane distances from the frustum origin
//==============================================================================
		void SetNearFarDistance (float NearDist, float FarDist);

//==============================================================================
// Updates the frustum orientation
//==============================================================================
		void UpdateOrientation (VEC3F Pos, VEC3F Up, VEC3F Forward, VEC3F Right);

//==============================================================================
// Gets the center of a plane
//==============================================================================
		VEC3F GetNearCenter ();
		VEC3F GetFarCenter ();

//==============================================================================
// Gets the width / height of a plane
//==============================================================================
		float GetNearPlaneWidth ();
		float GetNearPlaneHeight ();
		float GetFarPlaneWidth ();
		float GetFarPlaneHeight ();

//==============================================================================
// Calculates the corners of the frustum
//==============================================================================
		void CalculateCorners ();

//==============================================================================
// Clears the list of intersections
//==============================================================================
		void ClearIntersections ();

//==============================================================================
// Calculates Frustum - Plane intersections
//==============================================================================
		void IntersectPlane (PLANE3F &Plane);

//==============================================================================
// Calculates the frustum corners and renders its frame
//==============================================================================
		void glRenderFrame (COL3F Color);
};

}

#endif //G3_FRUSTUM_H
